package com.t3go.t3_map.base;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.location.Location;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;

import com.shareware.common.ApplicationKt;
import com.shareware.common.listener.Callback;
import com.shareware.common.utils.LogExtKt;
import com.shareware.common.utils.ScreenExtKt;
import com.t3go.passenger.base.utils.DensityUtil;
import com.t3go.passenger.base.utils.JsonUtils;
import com.t3go.passenger.base.utils.SP;
import com.t3go.t3_map.R;
import com.t3go.t3_map.business.common.CommonMapHelper;
import com.t3go.t3_map.business.valuation.ValuationMapHelper;
import com.t3go.t3_map.business.wait.WaitMapHelper;
import com.t3go.t3_map.entity.Annotation;
import com.t3go.t3_map.entity.AnnotationStyle;
import com.t3go.t3_map.entity.Annotations;
import com.t3go.t3_map.entity.BubbleType;
import com.t3go.t3_map.entity.CameraPosition;
import com.t3go.t3_map.entity.CenterPoint;
import com.t3go.t3_map.entity.Coordinate;
import com.t3go.t3_map.entity.EdgeInsets;
import com.t3go.t3_map.entity.LabelInfo;
import com.t3go.t3_map.entity.Offset;
import com.t3go.t3_map.entity.Polyline;
import com.t3go.t3_map.entity.ShowAnnotationArgs;
import com.t3go.t3_map.entity.ShowPolylineArgs;
import com.t3go.t3_map.entity.SuitableEntity;
import com.t3go.t3_map.service.LocationRouterServiceImpl;
import com.t3go.t3_map.service.MapFoundationServiceImpl;
import com.t3go.t3_map.utils.AnnotationUtil;
import com.t3go.t3_map.utils.MapConfig;
import com.t3go.t3_map.utils.MapDataUtil;
import com.t3go.t3_map.utils.MapUtils;
import com.t3go.t3_map.utils.MarkerUtil;
import com.t3go.t3_map.utils.PolylineUtils;
import com.t3map.api.T3MapsInitializer;
import com.t3map.api.location.T3LocationManagerService;
import com.t3map.api.location.entity.T3MapLocation;
import com.t3map.api.map.T3CameraUpdate;
import com.t3map.api.map.T3CameraUpdateFactory;
import com.t3map.api.map.T3Map;
import com.t3map.api.map.T3MapView;
import com.t3map.api.map.T3UiSettings;
import com.t3map.api.map.model.T3BitmapDescriptorFactory;
import com.t3map.api.map.model.T3CameraPosition;
import com.t3map.api.map.model.T3CustomMapStyleOptions;
import com.t3map.api.map.model.T3LatLng;
import com.t3map.api.map.model.T3LatLngBounds;
import com.t3map.api.map.model.T3Marker;
import com.t3map.api.map.model.T3MyLocationStyle;
import com.t3map.api.map.model.T3Polyline;
import com.t3map.api.map.model.T3PolylineOptions;
import com.t3map.core.map.T3LocationSource;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;
import io.reactivex.disposables.Disposable;

public class T3FMapPlatformView implements PlatformView, DefaultLifecycleObserver,
        ActivityPluginBinding.OnSaveInstanceStateListener, MethodChannel.MethodCallHandler {
    private static final String TAG = "T3FMapPlatformView";
    private final MethodChannel methodChannel;
    private boolean disposed = false;
    private final Context mContext;
    private Disposable timeObservable;
    private T3MyLocationStyle mStyle;
    private T3MapView mMapView;
    private T3Map mT3Map;

    private T3LatLng mCenterCoordinate;

    private final Map<String, List<T3Marker>> mMarkerMap = new HashMap<>();
    private final Map<String, T3Polyline> mPolylineMap = new HashMap<>();

    T3LatLng currentLatLng;

    private boolean mCameraChanging;

    private CommonMapHelper mCommonMapHelper;
    private ValuationMapHelper mValuationMapHelper;
    private WaitMapHelper mWaitMapHelper;

    /**
     * 路线上的标签
     */
    private T3Marker mLabelMarker;

    T3FMapPlatformView(int id, Context context, BinaryMessenger binaryMessenger,
                       LifecycleProvider lifecycleProvider, Object args) {
        mContext = context;
        Map<String, Object> params;
        int mapType = T3MapsInitializer.MAP_TYPE_AMAP;
        String mapId = "";
        try {
            params = (Map<String, Object>) args;
            LogExtKt.log(TAG, " create params==> " + params);
            if (params.containsKey("mapType")) {
                mapType = (int) params.get("mapType");
            }
            if (params.containsKey("mapId")) {
                mapId = (String) params.get("mapId");
            }

            CameraPosition cameraPosition = JsonUtils.fromJson(JsonUtils.toJson(params.get("initialCameraPosition")), CameraPosition.class);
            if (cameraPosition != null) {
                Coordinate coordinate = cameraPosition.getCenterCoordinate();
                if (coordinate != null && coordinate.getLatitude() > 0 && coordinate.getLongitude() > 0) {
                    mCenterCoordinate = new T3LatLng(coordinate.getLatitude(), coordinate.getLongitude());
                }
            }

        } catch (Throwable e) {
            LogExtKt.logStackTrace(TAG, e);
        }

        methodChannel = new MethodChannel(binaryMessenger, "t3_map_flutter_map_" + mapId);
        methodChannel.setMethodCallHandler(this);

        try {
            if (mapType != T3MapsInitializer.MAP_TYPE_AMAP && mapType != T3MapsInitializer.MAP_TYPE_TENCENT) {
                mapType = T3MapsInitializer.MAP_TYPE_AMAP;
            }
            mMapView = new T3MapView(context, mapType);
            initMapView();
            lifecycleProvider.getLifecycle().addObserver(this);
            setTencentLocation();
            initMapListener();

            if (mCenterCoordinate != null) {
                mT3Map.moveCamera(T3CameraUpdateFactory.newLatLngZoom(mCenterCoordinate, 16));
            }
        } catch (Throwable e) {
            LogExtKt.log(TAG, e.getMessage());
        }
    }

    private T3LocationSource.OnLocationChangedListener locationChangedListener;

    private final Callback<T3MapLocation> callback = new Callback<T3MapLocation>() {
        @Override
        public void call(T3MapLocation result) {
            if (locationChangedListener != null && result != null) {
                Location location = new Location(result.getLocationType() + "");
                //设置经纬度以及精度
                location.setLatitude(result.getLat());
                location.setLongitude(result.getLng());
                location.setAccuracy(result.getAccuracy());
                try {
                    location.setBearing(result.getBearing());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                locationChangedListener.onLocationChanged(location);
            }
        }
    };

    private void setTencentLocation() {
        T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).initSeriesLocation(6000);
        T3LocationSource locationSource = new T3LocationSource() {
            @Override
            public void activate(OnLocationChangedListener onLocationChangedListener) {
                locationChangedListener = onLocationChangedListener;
                T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).startSeriesLocation(callback);
            }

            @Override
            public void deactivate() {
                T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).stopSeriesLocation(callback);
            }
        };
        //设置定位源
        if (mT3Map != null) {
            mT3Map.setLocationSource(locationSource);
        }
    }


    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        LogExtKt.log(TAG, "onMethodCall -> method = " + call.method + ", arguments = " + call.arguments);
        String methodId = call.method;
        String arguments = call.arguments != null ? call.arguments.toString() : null;
        if (methodId.equals("polylines#add")) {// 添加线段
            addPolyline(arguments);
            result.success(true);
        } else if (methodId.equals("polylines#update")) {// 更新线段
            updatePolyline(arguments);
            result.success(true);
        } else if (methodId.equals("polylines#remove")) {// 移除线段
            removePolyline(arguments);
            result.success(true);
        } else if (methodId.equals("polylines#show")) {// 在可视区域内显示Polyline
            showSuitablePolyline(arguments);
            result.success(true);
        } else if (methodId.equals("map#userLocationVisible")) {//当前位置再地图中是否可见
            LogExtKt.log(TAG, "userLocationVisible ->");
            result.success(true);
        } else if (methodId.equals("map#userTrackingMode")) {//定位用户位置的模式
            try {
                JSONObject obj = new JSONObject(arguments);
                obj.optInt("mode");
                LocationRouterServiceImpl mRouterService = new LocationRouterServiceImpl();
                mRouterService.initSeriesLocation();
                if (obj.optBoolean("animated")) {
                    mRouterService.startSeriesLocation();
                } else {
                    mRouterService.stopSeriesLocation();
                }
                result.success(true);
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
        } else if (methodId.equals("map#showsUserLocation")) {// 是否显示用户位置
            try {
                JSONObject obj = new JSONObject(arguments);
                if (obj.optBoolean("visible")) {
                    showLocationIcon();
                } else {
                    hideLocationIcon();
                }
                result.success(true);
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
        } else if (methodId.equals("annotation#add")) {// 标记物-增加
            addAnnotations(arguments);
            result.success(true);
        } else if (methodId.equals("annotation#update")) {// 标记物-更新
            updateAnnotation(arguments);
            result.success(true);
        } else if (methodId.equals("annotation#remove")) {// 标记物-删除
            LogExtKt.log(TAG, "annotation#remove ->");
            removeAnnotations(arguments);
            result.success(true);
        } else if (methodId.equals("annotation#show")) {// 标记物-显示
            LogExtKt.log(TAG, "annotation#show ->");
            showSuitableAnnotations(arguments);
            result.success(true);
        } else if (methodId.equals("map#mapViewZoomLevel")) {
            try {
                JSONObject obj = new JSONObject(arguments);
                int level = obj.optInt("level", 17);
                boolean animated = obj.optBoolean("animated");
                if (currentLatLng != null) {
                    T3CameraUpdate cameraUpdate = T3CameraUpdateFactory.newCameraPosition(
                            new T3CameraPosition(currentLatLng, level, 0, 0));
                    mT3Map.animateCamera(cameraUpdate);
                }
                result.success(true);
            } catch (JSONException e) {
                result.success(true);
                LogExtKt.logStackTrace(TAG, e);
            }// 设置地图缩放级别
        } else if (methodId.equals("map#mapViewCenter")) { // 设置地图中心点
            CenterPoint centerPoint = JsonUtils.fromJson(arguments, CenterPoint.class);
            mT3Map.setPointToCenter(ScreenExtKt.getScreenWidth() / 2, (int) (0.5f * ScreenExtKt.getScreenHeight()),
                    ScreenExtKt.getScreenWidth(), ScreenExtKt.getScreenHeight());
            currentLatLng = new T3LatLng(centerPoint.getCoordinate().getLatitude(), centerPoint.getCoordinate().getLongitude());
            moveMap(currentLatLng, centerPoint.isAnimated());
            result.success(true);
        } else if (methodId.equals("map#showPolylinesAndAnnotations")) { // 在可视区域内显示Polyline和Annotation
            LogExtKt.log(TAG, "map#showPolylinesAndAnnotations ->");
            showPolylineAndAnnotations(arguments);
            result.success(true);
        } else if (methodId.equals("map#screenAnchor")) {
            screenAnchor(arguments);
            result.success(true);
        } else if (methodId.equals("map#mapViewGetCenterCoordinate")) {
            T3CameraPosition position = mT3Map.getCameraPosition();
            HashMap<String, Double> coordinate = new HashMap<>();
            if (position != null && position.target != null) {
                coordinate.put("latitude", position.target.lat);
                coordinate.put("longitude", position.target.lng);
            }
            result.success(JsonUtils.toJson(coordinate));
        } else {
            result.notImplemented();
        }
    }

    private void addAnnotations(String json) {
        LogExtKt.log(TAG, "addAnnotations -> json = " + json);
        Annotations annotations = JsonUtils.fromJson(json, Annotations.class);
        if (annotations == null || annotations.getAnnotations() == null) {
            return;
        }

        List<Annotation> list = annotations.getAnnotations();
        for (int i = 0; i < list.size(); i++) {
            try {
                addAnnotation(list.get(i));
            } catch (Exception e) {
                e.printStackTrace();
                LogExtKt.log(TAG, e.getMessage());
            }
        }
    }

    private void addAnnotation(Annotation data) {
        List<T3Marker> markers = null;
        if (AnnotationStyle.BUBBLE.equals(data.getStyle())) {
            markers = addBubbleMarker(data);
        } else if (AnnotationStyle.PIN.equals(data.getStyle())) {
            markers = addPinMarker(data);
        } else if (AnnotationStyle.WAIT.equals(data.getStyle())) {
            markers = addWaitMarker(data);
        } else {
            LogExtKt.log(TAG, "addAnnotation -> 不支持，style = " + data.getStyle());
        }
        mMarkerMap.put(data.getUid(), markers);
    }

    private List<T3Marker> addBubbleMarker(Annotation data) {
        if (data == null || data.getArgs() == null) {
            return null;
        }
        String bubbleType = AnnotationUtil.getBubbleType(data);
        if (BubbleType.VALUATION.equals(bubbleType)) {
            if (mValuationMapHelper == null) {
                mValuationMapHelper = new ValuationMapHelper(mContext, mT3Map);
            }
            return mValuationMapHelper.addBubble(data);
        } else {
            LogExtKt.log(TAG, "addBubble -> 类型不支持，bubbleType = " + bubbleType);
            return null;
        }
    }

    private List<T3Marker> addPinMarker(Annotation data) {
        if (data == null || data.getArgs() == null) {
            return null;
        }
        if (mCommonMapHelper == null) {
            mCommonMapHelper = new CommonMapHelper(mContext, mT3Map);
        }
        T3Marker marker = mCommonMapHelper.addPinMarker(data);
        if (marker != null) {
            return Collections.singletonList(marker);
        }
        return null;
    }

    private List<T3Marker> addWaitMarker(Annotation data) {
        if (mWaitMapHelper == null) {
            mWaitMapHelper = new WaitMapHelper(mContext, mT3Map);
            mWaitMapHelper.setRouteGuideListener(this::didTapAnnotation);
        }
        T3Marker marker = mWaitMapHelper.addWaitingMarker(data);
        if (marker != null) {
            return Collections.singletonList(marker);
        }
        return null;
    }

    private void updateAnnotation(String data) {
        LogExtKt.log(TAG, "updateAnnotation -> data = " + data);
        Annotation annotation = JsonUtils.fromJson(data, Annotation.class);
        try {
            if (AnnotationStyle.BUBBLE.equals(annotation.getStyle())) {
                updateBubbleMarker(annotation);
            } else if (AnnotationStyle.PIN.equals(annotation.getStyle())) {
                updatePinMarker(annotation);
            } else if (AnnotationStyle.WAIT.equals(annotation.getStyle())) {
                if (mWaitMapHelper == null) {
                    LogExtKt.log(TAG, "mWaitMapHelper == null");
                    return;
                }
                List<T3Marker> markers = mMarkerMap.get(annotation.getUid());
                if (markers != null && !markers.isEmpty()) {
                    mWaitMapHelper.updateWaitingMarker(markers.get(0), annotation);
                } else {
                    LogExtKt.log(TAG, "markers == null");
                }
            } else {
                LogExtKt.log(TAG, "updateAnnotation -> 不支持，style = " + annotation.getStyle());
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogExtKt.log(TAG, e.getMessage());
        }
    }

    private void updateBubbleMarker(Annotation annotation) {
        String bubbleType = AnnotationUtil.getBubbleType(annotation);
        if (BubbleType.VALUATION.equals(bubbleType)) {
            List<T3Marker> markers = mMarkerMap.get(annotation.getUid());
            if (markers != null && !markers.isEmpty()) {
                if (mValuationMapHelper == null) {
                    mValuationMapHelper = new ValuationMapHelper(mContext, mT3Map);
                }
                mValuationMapHelper.updateBubble(markers, annotation);
            } else {
                LogExtKt.log(TAG, "updateBubble -> error, marker 不存在");
            }
        } else {
            LogExtKt.log(TAG, "updateBubble -> 类型不支持，bubbleType = " + bubbleType);
        }
    }

    private void updatePinMarker(Annotation annotation) {
        List<T3Marker> markers = mMarkerMap.get(annotation.getUid());
        if (markers != null && !markers.isEmpty()) {
            if (mCommonMapHelper != null) {
                mCommonMapHelper.updatePinMarker(markers.get(0), annotation);
            }
        } else {
            LogExtKt.log(TAG, "updateBubble -> error, marker 不存在");
        }
    }

    private void removeAnnotations(String json) {
        Annotations annotations = JsonUtils.fromJson(json, Annotations.class);
        if (annotations == null || annotations.getAnnotations() == null) {
            return;
        }
        List<Annotation> list = annotations.getAnnotations();
        for (Annotation item : list) {
            List<T3Marker> markers = mMarkerMap.remove(item.getUid());
            if (markers == null || markers.isEmpty()) {
                continue;
            }
            for (T3Marker marker : markers) {
                if (marker == null) {
                    continue;
                }
                if (mWaitMapHelper != null && mWaitMapHelper.isWaitingMarker(marker)) {
                    mWaitMapHelper.removeWaitingMarker();
                }
                marker.remove();
            }
        }
    }

    private void addPolyline(String json) {
        try {
            addPolyline(JsonUtils.fromJson(json, Polyline.class));
        } catch (Exception e) {
            e.printStackTrace();
            LogExtKt.log(TAG, "addPolyline -> exception = " + e.getMessage());
        }
    }

    private void addPolyline(Polyline data) {
        if (data == null) {
            return;
        }
        String lineId = data.getUid();

        T3Polyline polyline = mPolylineMap.get(lineId);
        if (polyline != null) {
            polyline.remove();
        }

        List<T3LatLng> points = data.getPoints();
        if (points == null || points.isEmpty()) {
            return;
        }

        Polyline.StyleBean style = data.getStyle();
        if (style == null) {
            LogExtKt.log(TAG, "addPolyline -> style == null");
            return;
        }

        Map<Integer, Integer> trafficLevel = MapDataUtil.parseTrafficLevel(style.getTraffic());
        List<Integer> textureIndex = PolylineUtils.getTextureIndex(points, trafficLevel);

        T3PolylineOptions options = new T3PolylineOptions();
        options.visible(true)
                .addAll(points)
                .level(1)
                .width(ScreenExtKt.dp2px(style.getWidth()))
                .zIndex(style.isSelected() ? 2 : 1);

        if (textureIndex != null && !textureIndex.isEmpty()) {
            options.setCustomTextureIndex(textureIndex);
            options.setCustomTextureList(PolylineUtils.getTexturesList(style.isSelected()));
            options.width(options.getWidth() * 3); // TODO 设置纹理后，宽度变窄了
        } else {
            // 加入对应的颜色,使用colorValues 即表示使用多颜色，使用color表示使用单色线
            if (!TextUtils.isEmpty(style.getFillColorValue())) {
                options.color(Color.parseColor(style.getFillColorValue()));
            }
        }

        polyline = mT3Map.addPolyline(options);
        if (polyline != null) {
            mPolylineMap.put(lineId, polyline);
        }

        if (style.isSelected()) {
            addRouteLabelMarker(lineId, polyline, data.getLabel());
        }
    }

    private void updatePolyline(String json) {
        try {
            updatePolyline(JsonUtils.fromJson(json, Polyline.class));
        } catch (Exception e) {
            e.printStackTrace();
            LogExtKt.log(TAG, "addPolyline -> exception = " + e.getMessage());
        }
    }

    private void updatePolyline(Polyline data) {
        if (data == null) {
            return;
        }
        T3Polyline polyline = mPolylineMap.get(data.getUid());
        if (polyline == null) {
            LogExtKt.log(TAG, "updatePolyline -> 路线不存在, lineId = " + data.getUid());
            return;
        }
        List<T3LatLng> points = data.getPoints();
        if (points == null || points.isEmpty()) {
            return;
        }

        Polyline.StyleBean style = data.getStyle();
        if (style == null) {
            LogExtKt.log(TAG, "addPolyline -> style == null");
            return;
        }

        polyline.setPoints(points);
        polyline.setZIndex(style.isSelected() ? 2 : 1);
        polyline.setWidth(ScreenExtKt.dp2px(style.getWidth()));

        Map<Integer, Integer> trafficLevel = MapDataUtil.parseTrafficLevel(style.getTraffic());
        List<Integer> textureIndex = PolylineUtils.getTextureIndex(points, trafficLevel);
        if (textureIndex != null && !textureIndex.isEmpty()) {
            polyline.setCustomTextureIndex(textureIndex);
            polyline.setCustomTextureList(PolylineUtils.getTexturesList(style.isSelected()));
            polyline.setWidth(polyline.getWidth() * 3); // TODO 设置纹理后，宽度变窄了
        } else {
            // 加入对应的颜色,使用colorValues 即表示使用多颜色，使用color表示使用单色线
            if (!TextUtils.isEmpty(style.getFillColorValue())) {
                polyline.setColor(Color.parseColor(style.getFillColorValue()));
            }
        }
    }

    private void removePolyline(String json) {
        Polyline data = JsonUtils.fromJson(json, Polyline.class);
        if (data == null || TextUtils.isEmpty(data.getUid())) {
            return;
        }
        T3Polyline polyline = mPolylineMap.remove(data.getUid());
        if (polyline != null) {
            polyline.remove();
        }

        if (mLabelMarker != null && mLabelMarker.getObject() instanceof String) {
            String labelId = (String) mLabelMarker.getObject();
            if (labelId != null && labelId.equals(data.getUid())) {
                mLabelMarker.remove();
                mLabelMarker = null;
            }
        }
    }

    private void addRouteLabelMarker(String id, T3Polyline polyline, LabelInfo labelInfo) {
        if (mLabelMarker != null) {
            mLabelMarker.remove();
            mLabelMarker = null;
        }

        if (labelInfo == null) {
            return;
        }

        List<T3LatLng> points = polyline.getPoints();
        if (points == null || points.size() < 2) {
            return;
        }

        T3LatLng start = points.get(0);
        T3LatLng end = points.get(points.size() - 1);

        if (mCommonMapHelper == null) {
            mCommonMapHelper = new CommonMapHelper(mContext, mT3Map);
        }
        mLabelMarker = mCommonMapHelper.drawLabel(labelInfo, polyline, start, end);
        mLabelMarker.setObject(id);
    }

    private void showSuitableAnnotations(String json) {
        ShowAnnotationArgs data = JsonUtils.fromJson(json, ShowAnnotationArgs.class);
        if (data == null) {
            return;
        }
        List<T3LatLng> points = new ArrayList<>();
        List<Annotation> annotations = data.getAnnotations();
        if (annotations != null) {
            for (Annotation item : annotations) {
                if (item != null && item.getLatitude() > 0 && item.getLongitude() > 0) {
                    points.add(new T3LatLng(item.getLatitude(), item.getLongitude()));
                }
            }
        }
        showSuitableCamera(data.getEdgeInsets(), points, data.isAnimated());
    }

    public void showSuitablePolyline(String json) {
        ShowPolylineArgs data = JsonUtils.fromJson(json, ShowPolylineArgs.class);
        if (data == null || data.getPolylines() == null) {
            return;
        }
        List<T3LatLng> points = new ArrayList<>();
        for (Polyline item : data.getPolylines()) {
            if (item != null && item.getPoints() != null) {
                points.addAll(item.getPoints());
            }
        }
        showSuitableCamera(data.getEdgeInsets(), points, data.isAnimated());
    }

    public void showSuitableCamera(EdgeInsets edge, List<T3LatLng> points, boolean animated) {
        LogExtKt.log(TAG, "showSuitableCamera ->");
        if (points == null || points.isEmpty()) {
            return;
        }
        MapFoundationServiceImpl service = new MapFoundationServiceImpl();
        if (points.size() == 1) {
            moveMap(points.get(0), edge, animated);
            return;
        }

        T3LatLngBounds.Builder builder = T3LatLngBounds.builder();
        for (T3LatLng latLng : points) {
            builder.include(latLng);
        }
        T3LatLngBounds bounds = builder.build();
        if (bounds.northeast != null
                && bounds.southwest != null
                && bounds.northeast.lat - bounds.southwest.lat < 0.000005
                && bounds.northeast.lng - bounds.southwest.lng < 0.000005) {
            service.animateMoveMap_16(mT3Map, bounds.northeast);
        } else {
            if (edge == null) {
                edge = new EdgeInsets();
            }
            int left = ScreenExtKt.dp2px(Double.valueOf(edge.getLeft()).floatValue());
            int top = ScreenExtKt.dp2px(Double.valueOf(edge.getTop()).floatValue());
            int right = ScreenExtKt.dp2px(Double.valueOf(edge.getRight()).floatValue());
            int bottom = ScreenExtKt.dp2px(Double.valueOf(edge.getBottom()).floatValue());
            if (animated) {
                service.animateMoveMapBynNewLatLngBoundsRect(mT3Map, bounds, left, right, top, bottom);
            } else {
                service.moveMapBynNewLatLngBoundsRect(mT3Map, bounds, left, right, top, bottom);
            }
        }
    }

    private void moveMap(T3LatLng latLng, EdgeInsets edge, boolean animated) {
        if (latLng == null || mMapView == null || mT3Map == null) {
            return;
        }
        T3LatLng newLatLng = null;
        try {
            if (edge != null) {
                int verticalOffset = DensityUtil.dp2px((int) ((edge.getBottom() - edge.getTop()) / 2));
                int horizontalOffset = DensityUtil.dp2px((int) ((edge.getRight() - edge.getLeft()) / 2));

                int mapCenterX = mMapView.getWidth() / 2;
                int mapCenterY = mMapView.getHeight() / 2;
                int y = mapCenterY - verticalOffset;
                int x = mapCenterX - horizontalOffset;

                // 原始起点在屏幕中的位置
                Point point = mT3Map.getProjection().toScreenLocation(latLng);
                int diffY = point.y - y;
                int diffX = point.x - mapCenterX;

                // 根据原起点的位置 计算的移动后 地图中心的坐标
                Point newPoint = new Point(mapCenterX + diffX, mapCenterY + diffY);
                newLatLng = mT3Map.getProjection().fromScreenLocation(newPoint);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (newLatLng == null) {
            newLatLng = latLng;
        }

        MapFoundationServiceImpl service = new MapFoundationServiceImpl();
        if (animated) {
            service.animateMoveMapByNewLatLng(mT3Map, newLatLng);
        } else {
            service.moveMapByNewCameraPosition(mT3Map, newLatLng);
        }
    }

    public void moveMap(T3LatLng latLng, boolean animated) {
        if (latLng == null) {
            return;
        }
        MapFoundationServiceImpl service = new MapFoundationServiceImpl();
        if (animated) {
            service.animateMoveMap_17(mT3Map, latLng);
        } else {
            service.animateMoveMap_17(mT3Map, latLng, 1);
        }
    }

    public void showPolylineAndAnnotations(String json) {
        SuitableEntity data = JsonUtils.fromJson(json, SuitableEntity.class);
        if (data == null || (data.getPolylines() == null && data.getAnnotations() == null)) {
            return;
        }
        List<T3LatLng> points = new ArrayList<>();

        List<Polyline> lines = data.getPolylines();
        if (lines != null) {
            for (Polyline item : lines) {
                if (item != null && item.getPoints() != null) {
                    points.addAll(item.getPoints());
                }
            }
        }

        List<Annotation> annotations = data.getAnnotations();
        if (annotations != null) {
            for (Annotation item : annotations) {
                if (item != null && item.getLatitude() > 0 && item.getLongitude() > 0) {
                    points.add(new T3LatLng(item.getLatitude(), item.getLongitude()));
                }
            }
        }

        showSuitableCamera(data.getEdgeInsets(), points, data.isAnimated());
    }

    /**
     * 设置地图中心点
     */
    private void screenAnchor(String json) {
        LogExtKt.log(TAG, "screenAnchor -> json = " + json);
        Offset offset = fromJson(json, "offset", Offset.class);
        if (offset != null) {
            int x = (int) (mMapView.getWidth() * offset.getX());
            int y = (int) (mMapView.getHeight() * offset.getY());
            LogExtKt.log(TAG, "screenAnchor -> x = " + x + ", y = " + y);
            mT3Map.setPointToCenter(x, y, mMapView.getWidth(), mMapView.getHeight());
        }
    }


    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        LogExtKt.log(TAG, "onCreate==>");
        try {
            if (disposed) {
                return;
            }
            if (null != mMapView) {
                mMapView.onCreate(null);
            }
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onCreate" + e.getMessage());
        }
    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        if (mMapView != null) {
            mMapView.onStart();
        }
        LogExtKt.log(TAG, "onStart==>");
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        LogExtKt.log(TAG, "onResume==>");
        try {
            if (disposed) {
                return;
            }
            if (mMapView != null) {
                mMapView.onResume();
            }
//            if (mapController != null) {
//                mapController.setMyLocationVisible(true);
//            }
            if (mWaitMapHelper != null) {
                mWaitMapHelper.onResume();
            }

        } catch (Throwable e) {
            LogExtKt.log(TAG, "onResume " + e.getMessage());
        }
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        LogExtKt.log(TAG, "onPause==>");
        try {
            if (disposed) {
                return;
            }
            if (mMapView != null) {
                mMapView.onPause();
            }
//            if (mapController != null) {
//                mapController.setMyLocationVisible(false);
//            }
            if (mWaitMapHelper != null) {
                mWaitMapHelper.onPause();
            }
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onPause " + e.getMessage());
        }
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        LogExtKt.log(TAG, "onStop==>");
        try {
            if (disposed) {
                return;
            }
            if (mMapView != null) {
                mMapView.onStop();
            }
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onStop " + e.getMessage());
        }
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        LogExtKt.log(TAG, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            if (mMapView != null) {
                mMapView.onDestroy();
            }
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onDestroy " + e.getMessage());
        }
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle bundle) {
        LogExtKt.log(TAG, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            mMapView.onSaveInstanceState(bundle);
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onSaveInstanceState " + e.getMessage());
        }
    }

    @Override
    public void onRestoreInstanceState(@Nullable Bundle bundle) {
        LogExtKt.log(TAG, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            mMapView.onCreate(bundle);
        } catch (Throwable e) {
            LogExtKt.log(TAG, "onRestoreInstanceState " + e.getMessage());
        }
    }


    @Override
    public View getView() {
        LogExtKt.log(TAG, "getView==>");
        return mMapView;
    }

    @Override
    public void dispose() {
        LogExtKt.log(TAG, "dispose==>");
        try {
            if (disposed) {
                return;
            }
            methodChannel.setMethodCallHandler(null);
            if (mMapView != null) {
                mMapView.onDestroy();
            }
            disposed = true;
        } catch (Throwable e) {
            LogExtKt.log(TAG, e.getMessage());
        }
    }

    private void initMapView() {
        // 此方法必须重写
        mMapView.onCreate(null);
        // 地图的一些 ui 设置
        if (mT3Map == null) {
            mT3Map = mMapView.getMap();
        }
        // 设置地图默认渲染模式
        mT3Map.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        //UI说从漠河下单到乌鲁木齐，屏幕内没办法显示全，所以，设置最小的比例
        mT3Map.setMinZoomLevel(3);
        mT3Map.setMaxZoomLevel(20);
        T3UiSettings settings = mT3Map.getUiSettings();
        settings.setGestureScaleByMapCenter(true);//开启中心为手势中心
        settings.setZoomGesturesEnabled(true);//设置双击地图放大在地图中心位置放大
        settings.setScrollGesturesEnabled(true);
        settings.setRotateGesturesEnabled(false);//旋转手势
        settings.setTiltGesturesEnabled(false);//双指倾斜手势
        // 缩放控件
        settings.setZoomControlsEnabled(false);//是否允许显示地图缩放按钮
        // 与地图交互 --- end

        // 获取配置时间间隔
        long interval = 3000;
        try {
            interval = new SP(ApplicationKt.getContextGlobal()).getLong("aMapLocationInterval") * 1000;
            interval = interval > 0 ? interval : 3000;
        } catch (Exception e) {
            e.printStackTrace();
        }
        LogExtKt.log(TAG, "map location interval=" + interval);
        // 设置定位图标
        mStyle = new T3MyLocationStyle()
                .strokeColor(Color.argb(60, 50, 137, 250))
                .radiusFillColor(Color.argb(25, 50, 137, 250))
                .anchor(0.5f, 0.8f)
                .interval(interval)
                .myLocationType(T3MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)
                .myLocationIcon(T3BitmapDescriptorFactory.fromResource(R.drawable.map_current_location))
                .showMyLocation(true);


        long finalInterval = interval;
        T3LocationSource locationSource = new T3LocationSource() {
            @Override
            public void activate(OnLocationChangedListener onLocationChangedListener) {
                LogExtKt.log(TAG, "getMyLocation Series start interval=" + finalInterval);
                timeObservable = MapSourceHelper.activeLocationSource(finalInterval, onLocationChangedListener);
            }

            @Override
            public void deactivate() {
                LogExtKt.log(TAG, "getMyLocation Series stop");
                MapSourceHelper.deactivateLocationSource(timeObservable);
            }
        };
        //设置定位源
        mT3Map.setLocationSource(locationSource);
        // 定位小蓝点 ------ end

        setMapCustomFile(mT3Map);
    }

    private void setMapCustomFile(T3Map t3Map) {
        try {
            if (mContext == null) {
                return;
            }
            InputStream inputStream = mContext.getAssets().open(MapConfig.CUSTOM_MAP_FILE_NAME);
            byte[] b = new byte[inputStream.available()];
            inputStream.read(b);
            inputStream.close();
            T3CustomMapStyleOptions options = new T3CustomMapStyleOptions();
            //自定义样式，对应资源包中的style.data
            options.setStyleData(b);
            //样式额外的配置，比如路况，背景颜色等，对应资源包中的style_extra.data
            options.setStyleExtraData(b);
            t3Map.setCustomMapStyle(options);
        } catch (IOException e) {
            LogExtKt.logStackTrace(getClass().getSimpleName(), e);
        }
    }

    private void initMapListener() {
        if (mT3Map == null) {
            LogExtKt.log(TAG, "initMapListener -> error, mT3Map is null.");
            return;
        }

        mMapView.setOnMapTouchListener(new View.OnTouchListener() {
            private float startX;
            private float startY;
            private long downTime;
            private boolean doubleClick;

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    doubleClick = SystemClock.uptimeMillis() - downTime < 250;
                    downTime = SystemClock.uptimeMillis();
                    startX = event.getX();
                    startY = event.getY();
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    int slop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
                    if (Math.abs(event.getX() - startX) > slop || Math.abs(event.getY()) - startY > slop) {
                        LogExtKt.log(TAG, "用户移动了地图");
                        methodChannel.invokeMethod("map#onTouch", null);
                    } else if (doubleClick) {
                        LogExtKt.log(TAG, "用户双击地图");
                        methodChannel.invokeMethod("map#onTouch", null);
                    }
                }
                return false;
            }
        });


        mT3Map.setOnMapLoadedListener(() -> {
            LogExtKt.log(TAG, "地图加载完成");
            methodChannel.invokeMethod("map#initComplete", null);
        });

        mT3Map.setOnCameraChangeListener(new T3Map.OnCameraChangeListener() {
            @Override
            public void onCameraChange(T3CameraPosition cameraPosition) {
                if (cameraPosition == null) {
                    return;
                }
                if (!mCameraChanging) {
                    LogExtKt.log(TAG, "onCameraChange -> mCameraChanging = true");
                    mCameraChanging = true;
                    methodChannel.invokeMethod("map#regionWillChange", null);
                }

                HashMap<String, Object> arguments = new HashMap<>();
                arguments.put("zoomLevel", cameraPosition.zoom);
                if (cameraPosition.target != null) {
                    HashMap<String, Double> position = new HashMap<>();
                    position.put("longitude", cameraPosition.target.lng);
                    position.put("latitude", cameraPosition.target.lat);
                    arguments.put("coordinate", position);
                }
                methodChannel.invokeMethod("map#regionChanged", arguments);
            }

            @Override
            public void onCameraChangeFinish(T3CameraPosition cameraPosition) {
                mCameraChanging = false;
                LogExtKt.log(TAG, "onCameraChangeFinish -> mCameraChanging = false");

                HashMap<String, Object> arguments = new HashMap<>();
                arguments.put("animated", false);
                arguments.put("wasUserAction", false); // TODO Hunter
                methodChannel.invokeMethod("map#regionDidChange", arguments);
            }
        });

        mT3Map.setOnMarkerClickListener(marker -> {
            didTapAnnotation(marker);
            return true;
        });

        mT3Map.setOnPolylineClickListener(polyline -> {
            String uid = MapUtils.findPolylineId(mPolylineMap, polyline);
            LogExtKt.log(TAG, "onPolylineClick -> uid = " + uid);
            methodChannel.invokeMethod("map#didTapPolyline", uid);
        });
    }

    private void didTapAnnotation(T3Marker marker) {
        String uid = MarkerUtil.getMarkerId(mMarkerMap, marker);
        LogExtKt.log(TAG, "onMarkerClick -> uid = " + uid);
        if (TextUtils.isEmpty(uid)) {
            return;
        }
        HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("identifier", uid);
        methodChannel.invokeMethod("map#didTapAnnotation", JsonUtils.toJson(arguments));
    }

    private void showLocationIcon() {
        if (mT3Map != null && mStyle != null && enabledLocation()) {
            //每次设置定位图标可见的时候，需要重新设置一下style才可以
            mT3Map.setMyLocationStyle(mStyle);
            mT3Map.setMyLocationEnabled(true);
        }
    }

    private void hideLocationIcon() {
        if (mT3Map != null) {
            mT3Map.setMyLocationEnabled(false);
        }
    }

    protected boolean enabledLocation() {
        return true;
    }

    private static <T> T fromJson(String json, String key, Type typeOfT) {
        try {
            HashMap map = JsonUtils.fromJson(json, HashMap.class);
            return JsonUtils.fromJson(JsonUtils.toJson(map.get(key)), typeOfT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
